#include "../../plcc/log/log.h"
#include <unistd.h>
#include "../../plcc/thread/Thread.h"
#include "../../plcc/event_queue/EventQueue.h"
#include <iostream>
#include <string>

using namespace std;

class SetLog :public Thread {
 public:
  #define LOG_INFO(level)   log_type_.level_ = level; oss_ 
  #define LOG_ADD   do{\
                     log_type_.msg_ = oss_.str();\
                     log_->AddEvent(log_type_); oss_.str("");\
                    }while(0)
  SetLog(EventQueue<LogType>* log) :log_(log) { }

 private:
  virtual void Run() {
    for(int i=0;i<20;i++) {
      LOG_INFO(LOG_LEVEL_WARNING) << "SetLOG ## this is" << i << "'s SetLog" ; 
      LOG_ADD;
      cout << "SetLOG ## in_success "<<endl;
    } 
    sleep(10);

    //oss << "SetLOG ## this is end SetLog" ; 
    //log_->AddEvent(oss.str());
    //cout << "SetLOG ## in_success "<<endl;
    //oss.str("");

    cout<<"kkk"<<endl;
  }

 private:
  EventQueue<LogType>* log_;
  ostringstream oss_; 
  LogType log_type_;
};

class PlayLog :public Thread {
 public:
  #define LOG_INFO(level) log_type_.level_ = level; oss_ 
  #define LOG_ADD   do{\
                     log_type_.msg_ = oss_.str();\
                     log_->AddEvent(log_type_); oss_.str("");\
                    }while(0)
  PlayLog(EventQueue<LogType>* log) :log_(log) { }

 private:
  virtual void Run() {
    for(int i=0;i<10;i++) {
      LOG_INFO(LOG_LEVEL_INFO) << "PlayLOG ## this is" << i << "'s PlayLog" ; 
      LOG_ADD;
      cout << "PlayLOG ## in_success "<<endl;
    } 
    sleep(10);

  }

 private:
  ostringstream oss_; 
  EventQueue<LogType>* log_;
  LogType log_type_;
};


class LogOut :public Thread { 
 public:
  LogOut(EventQueue<LogType>* log) :log_(log) { }

 private:
  virtual void Run() {
    ENUM_LOG_LEVEL log_level = LOG_LEVEL_INFO;
    Logger* out= new Logger;

    out->LogConfig();
    if(!out->OpenFile()) {
      cerr<< "fatal error!" <<endl;
      pthread_exit((void*)2);
    }
     
    //out->SetLevel(log_level);

    for(;;) {
      if(out->IfRotateLog()) {
        out->RotateLog();
      }
       
      Type<LogType>* tmp = log_->GetEvent();
      log_level = (tmp->opcode()).level_;
      string str_tmp = (tmp->opcode()).msg_;
      cout <<"out_string == "<< str_tmp <<endl;
      out->SetLevel(log_level);
      out->log(str_tmp);
      delete tmp;
      sleep(1);
    }
    cout<<"end"<<endl;
    //out->CloseFile();
  }

 private:
  EventQueue<LogType>* log_;
};


int main(int argc, char* argv[]) {
  EventQueue<LogType>* log = new EventQueue<LogType>();
  SetLog *set_thread = new SetLog(log);
  PlayLog *play_thread = new PlayLog(log);
  LogOut *out_thread = new LogOut(log);

  set_thread->Start();
  play_thread->Start();
  out_thread->Start();

  set_thread->Join();
  play_thread->Join();
  out_thread->Join();
  cout << "Joined." << endl;
  return true;
}
